<?php

abstract class Kd_Model_Collection_Base extends Kd_Data_Dcl_Query implements Iterator, ArrayAccess, SeekableIterator, Serializable, Countable {

    protected $source = array();

    public function __construct() {
        parent::__construct();
    }

    public function __call($name, $arguments) {
        if (substr($name, 0, 8) == 'filterBy') {
            return $this->filterBy(strtolower(substr($name, 8)), isset($arguments[0]) ? $arguments[0] : NULL);
        }
        if (substr($name, 0, 6) == 'sortBy') {
            return $this->orderBy(strtolower(substr($name, 6)), isset($arguments[0]) ? $arguments[0] : 'asc');
        }
        return parent::__call($name, $arguments);
    }

    public function toArray() {
        $result = array();
        foreach ($this as $item) {
            if (is_object($item)) {
                $result[] = method_exists($item, 'toArray') ? $item->toArray() : $item;
            } else {
                $result[] = $item;
            }
        }
        return $result;
    }

    public function current() {
        return current($this->source);
    }

    public function key() {
        return key($this->source);
    }

    public function next() {
        next($this->source);
    }

    public function rewind() {
        reset($this->source);
    }

    public function valid() {
        return current($this->source) !== FALSE;
    }

    public function getItem($offset) {
        return $this->source[$offset];
    }

    public function getFirstItem() {
        $this->rewind();
        return current($this->source);
    }

    public function getLastItem() {
        return end($this->source);
    }

    public function unshift(){
        $args = func_get_args();
        foreach($args as $arg){
            array_unshift($this->source, $arg);
        }
        return $this;
    }

    public function append($item, $offset = NULL) {
        if ($offset === NULL) {
            $this->source[] = $item;
        } else {
            $this->source[$offset] = $item;
        }

        return $this;
    }

    public function remove($offset) {
        unset($this->source[$offset]);
        return $this;
    }

    public function clear() {
        $this->source = array();
        return $this;
    }

    public function merge(array $arr) {
        array_merge($this->source, $arr);
        return $this;
    }

    public function isEmpty() {
        return count($this->source) == 0;
    }

    public function count() {
        return count($this->source);
    }

    public function offsetExists($offset) {
        return isset($this->source[$offset]);
    }

    public function offsetGet($offset) {
        return $this->getItem($offset);
    }

    public function offsetSet($offset, $value) {
        $this->append($value, $offset);
    }

    public function offsetUnset($offset) {
        unset($this->source[$offset]);
    }

    public function seek($position) {
        throw new Exception('The seek method not support');
    }

    public function serialize() {
        return serialize($this->source);
    }

    public function unserialize($serialized) {
        $arr = unserialize($serialized);
        return new self($arr);
    }

    public function setItemPropertyValue($propertyName, $value) {
        foreach ($this as $item) {
            $item[$propertyName] = $value;
        }
        return $this;
    }

    public function getItemPropertyValue($propertyName) {
        $result = array();
        foreach ($this as $item) {
            $result[] = $item[$propertyName];
        }
        return $result;
    }

    public function loadCount() {
        return $this->fetchCount();
    }

    public function load() {
        return $this->fill($this->fetch()->toArray());
    }

    public function filterBy($name, $arg) {
        return $this;
    }

    public function sortBy($name, $dir) {
        return $this;
    }

    public abstract function fill(array $data);
}